import { 
  IChemistryObject, 
  IElement, 
  IElementPair, 
  IElementCombine, 
  IMolecularFormula,
  IElementCombinePair,
  IEquationPosition,
  IEquation,
  BalanceResult
} from '../types/chemistry'

// 基础化学对象类
export abstract class ChemistryObject implements IChemistryObject {
  protected _string: string = '';

  constructor(str: string = '') {
    this._string = str;
  }

  getString(): string {
    return this._string;
  }

  abstract getElements(): string[];
  abstract getElementCount(element: string): number;
}

// 化学元素类
export class Element extends ChemistryObject implements IElement {
  constructor(elementStr: string) {
    super(elementStr);
  }

  getElementString(): string {
    return this._string;
  }

  getElements(): string[] {
    return [this._string];
  }

  getElementCount(element: string): number {
    return this._string === element ? 1 : 0;
  }
}

// 元素对类（如 H2, O3）
export class ElementPair extends ChemistryObject implements IElementPair {
  private _element: Element;
  private _count: number;

  constructor(element: Element, count: number = 1) {
    super('');
    this._element = element;
    this._count = count;
  }

  getElement(): Element {
    return this._element;
  }

  getCount(): number {
    return this._count;
  }

  getString(): string {
    if (this._count === 1) {
      return this._element.getString();
    }
    return this._element.getString() + this._count.toString();
  }

  getElements(): string[] {
    return [this._element.getString()];
  }

  getElementCount(element: string): number {
    return this._element.getString() === element ? this._count : 0;
  }
}

// 元素组合类（如 SO4）
export class ElementCombine extends ChemistryObject implements IElementCombine {
  private _pairs: ElementPair[] = [];

  constructor() {
    super('');
  }

  append(pair: ElementPair): void {
    this._pairs.push(pair);
  }

  getString(): string {
    return this._pairs.map(pair => pair.getString()).join('');
  }

  getElements(): string[] {
    const elements: string[] = [];
    for (const pair of this._pairs) {
      const elementStr = pair.getElement().getElementString();
      if (!elements.includes(elementStr)) {
        elements.push(elementStr);
      }
    }
    return elements;
  }

  getElementCount(element: string): number {
    for (const pair of this._pairs) {
      if (pair.getElement().getElementString() === element) {
        return pair.getElementCount(element);
      }
    }
    return 0;
  }
}

// 带计数的元素组合对类（如 (SO4)3）
export class ElementCombinePair extends ChemistryObject implements IElementCombinePair {
  private _combine: ElementCombine;
  private _count: number;

  constructor(combine: ElementCombine, count: number = 1) {
    super('');
    this._combine = combine;
    this._count = count;
  }

  getCombine(): ElementCombine {
    return this._combine;
  }

  getCount(): number {
    return this._count;
  }

  getString(): string {
    if (this._count === 1) {
      return this._combine.getString();
    }
    return `(${this._combine.getString()})${this._count}`;
  }

  getElements(): string[] {
    return this._combine.getElements();
  }

  getElementCount(element: string): number {
    return this._count * this._combine.getElementCount(element);
  }
}

// 分子式类（如 Fe2(SO4)3）
export class MolecularFormula extends ChemistryObject implements IMolecularFormula {
  private _pairs: ElementCombinePair[] = [];

  constructor() {
    super('');
  }

  append(pair: ElementCombinePair): void {
    this._pairs.push(pair);
  }

  getString(): string {
    return this._pairs.map(pair => pair.getString()).join('');
  }

  getElements(): string[] {
    const elements: string[] = [];
    for (const pair of this._pairs) {
      const pairElements = pair.getElements();
      for (const element of pairElements) {
        if (!elements.includes(element)) {
          elements.push(element);
        }
      }
    }
    return elements;
  }

  getElementCount(element: string): number {
    let totalCount = 0;
    for (const pair of this._pairs) {
      totalCount += pair.getElementCount(element);
    }
    return totalCount;
  }
}

// 方程式位置类
export class EquationPosition implements IEquationPosition {
  private _formula: MolecularFormula;
  private _count: number = 1;

  constructor(formula: MolecularFormula) {
    this._formula = formula;
  }

  getMolecularFormula(): MolecularFormula {
    return this._formula;
  }

  setCount(count: number): void {
    this._count = count;
  }

  getCount(): number {
    return this._count;
  }

  getString(): string {
    let str = '';
    if (this._count > 1) {
      str += this._count.toString();
    }
    str += this._formula.getString();
    return str;
  }

  getElements(): string[] {
    return this._formula.getElements();
  }

  getElementCount(element: string): number {
    return this._count * this._formula.getElementCount(element);
  }
}

// 方程式位置集合类
export class EquationPositions {
  private _formulas: EquationPosition[] = [];

  append(position: EquationPosition): void {
    this._formulas.push(position);
  }

  getFormulasCount(): number {
    return this._formulas.length;
  }

  getFormula(index: number): EquationPosition | null {
    return index < this._formulas.length ? this._formulas[index] : null;
  }

  getElements(): string[] {
    const elements: string[] = [];
    for (const formula of this._formulas) {
      const formulaElements = formula.getElements();
      for (const element of formulaElements) {
        if (!elements.includes(element)) {
          elements.push(element);
        }
      }
    }
    return elements;
  }

  getElementCount(element: string): number {
    let count = 0;
    for (const formula of this._formulas) {
      count += formula.getElementCount(element);
    }
    return count;
  }

  getString(): string {
    return this._formulas.map(formula => formula.getString()).join(' + ');
  }

  equal(other: EquationPositions): boolean {
    const elements1 = this.getElements();
    const elements2 = other.getElements();
    
    if (elements1.length !== elements2.length) {
      return false;
    }

    for (const element of elements1) {
      if (!elements2.includes(element)) {
        return false;
      }
      
      const count1 = this.getElementCount(element);
      const count2 = other.getElementCount(element);
      
      if (count1 !== count2) {
        return false;
      }
    }
    
    return true;
  }
}